/*
 * Copyright (c) 2022. China Mobile (SuZhou) Software Technology Co.,Ltd. All rights reserved.
 * Lakehouse is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package com.chinamobile.cmss.lakehouse.service.redis;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

@Slf4j
public class RedisClient {
    private JedisPool pool;

    public void set(String key, Object value) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            jedis.set(key, value.toString());
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * Set ttl
     *
     * @param key
     * @param exptime
     * @throws Exception
     */
    public void setKeyExpireTime(String key, int exptime) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            jedis.expire(key, exptime);
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public void setWithExpireTime(String key, String value, int exptime) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            jedis.set(key, value, SetParams.setParams().nx().ex(300));
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.get(key);
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return null;
    }

    public List<String> mget(String... keys) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.mget(keys);
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return null;
    }

    public Set<String> keys(String pattern) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.keys(pattern);
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return null;
    }

    public Set<String> hkeys(String pattern) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.hkeys(pattern);
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return null;
    }

    public long del(String key) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            Long count = jedis.del(key);
            return count != null ? count : -1L;
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return 0;
    }

    public long del(String... keys) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            Long count = jedis.del(keys);
            return count != null ? count : -1L;
        } catch (Exception e) {
            log.error("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return 0;
    }

    public boolean getDistributeLock(String key, String value, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            String result = jedis.set(key, value, SetParams.setParams().nx().px(expireTime));
            return "OK".equals(result);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public boolean releaseDistributeLock(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));

            Long releaseSuccess = 1L;
            return releaseSuccess.equals(result);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public Long lpush(String key, String... value) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.lpush(key, value);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public Long rpush(String key, String... value) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.rpush(key, value);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public List<String> getAllListResult(String key) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.lrange(key, 0, -1);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public JedisPool getJedisPool() {
        return pool;
    }

    public void setJedisPool(JedisPool jedisPool) {
        this.pool = jedisPool;
    }

    public List<String> getAllSetReulst(String key, Set<Object> fields) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            String[] rawHashKeys = new String[fields.size()];
            int counter = 0;

            for (Object hashKey : fields) {
                rawHashKeys[counter++] = (String) hashKey;
            }

            return jedis.hmget(key, rawHashKeys);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get resource from pool", e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }

    }
}
